﻿using Caliburn.Micro;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using System.Xml.Linq;


namespace PhilipsChannelOrder.ViewModels
{
    public class ChangeOrderViewModel : PropertyChangedBase, IShell
    {


        private ObservableCollection<Models.ChannelNode> _channelMap;

        public ObservableCollection<Models.ChannelNode> ChannelMap
        {
            get { return _channelMap; }
            set
            {
                _channelMap = value;
                NotifyOfPropertyChange(() => ChannelMap);
            }
        }


        public void ReadXmlFile()
        {
            string selectedFolder = string.Empty;
            System.Windows.Forms.OpenFileDialog selectFolderDialog = new System.Windows.Forms.OpenFileDialog();

            if (selectFolderDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                _policyXmlPath = selectFolderDialog.FileName;
                System.IO.Stream ioStream = new System.IO.FileStream(_policyXmlPath, System.IO.FileMode.Open);
                var channelList = ParseFile(ioStream);
                ChannelMap = new ObservableCollection<Models.ChannelNode>(channelList);
            }
        }

        public void SaveXmlFile()
        {
            string selectedFolder = string.Empty;
            System.Windows.Forms.SaveFileDialog saveFileDialog = new System.Windows.Forms.SaveFileDialog();
            saveFileDialog.DefaultExt = "xml";
            if (saveFileDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                ListToDocument().Save(saveFileDialog.FileName, SaveOptions.OmitDuplicateNamespaces);
            }
        }

        private string _policyXmlPath;
        public string PolicyXmlPath
        {
            get
            {
                return _policyXmlPath;
            }
            set
            {
                _policyXmlPath = value;
            }
        }

        public IEnumerable<Models.ChannelNode> ParseFile(System.IO.Stream ioStream)
        {
            XDocument document = XDocument.Load(ioStream);
            var channels = from channel in document.Root.Elements("Channel")
                           select new Models.ChannelNode()
                           {
                               Name = channel.Element("Setup").Attribute("name").Value,
                               PresetNumber = Int32.Parse(channel.Element("Setup").Attribute("presetnumber").Value),
                               OldPresetNumber = Int32.Parse(channel.Element("Setup").Attribute("oldpresetnumber").Value),
                               Broadcast = channel.Element("Broadcast")
                           };
            
            return channels.OrderBy(ch => ch.PresetNumber);
        }

        public void ChannelUp(Models.ChannelNode channel)
        {
            int index = _channelMap.IndexOf(channel);
           
            if (index > 0)
            {
                int preset = _channelMap[index - 1].PresetNumber;

                _channelMap[index] = _channelMap[index - 1];
                _channelMap[index].PresetNumber = channel.PresetNumber;
                _channelMap[index - 1] = channel;
                _channelMap[index - 1].PresetNumber = preset;
            }
            NotifyOfPropertyChange(() => ChannelMap);
        }

        public void ChannelDown(Models.ChannelNode channel)
        {
            int index = _channelMap.IndexOf(channel);

            if (index < _channelMap.Count-1)
            {
                int preset = _channelMap[index + 1].PresetNumber;

                _channelMap[index] = _channelMap[index + 1];
                _channelMap[index].PresetNumber = channel.PresetNumber;
                _channelMap[index + 1] = channel;
                _channelMap[index + 1].PresetNumber = preset;
            }
           
        }

        private XDocument ListToDocument()
        {
            var xdoc = new XDocument(
                new XDeclaration("1.0", "utf-8", null),
                new XElement("ChannelMap",
                    _channelMap.Select(chann =>
                        new XElement("Channel",
                            new XElement("Setup",
                            new XAttribute("oldpresetnumber", chann.OldPresetNumber),
                            new XAttribute("presetnumber", chann.PresetNumber),
                            new XAttribute("name", chann.Name)
                        ),
                        chann.Broadcast
                        )
                    )
                )
            );
            return xdoc;
        }

        public void MoveToEnd(Models.ChannelNode channel)
        {
            _channelMap.Remove(channel);
            channel.PresetNumber = _channelMap.Last().PresetNumber + 1;
            _channelMap.Add(channel);

            NotifyOfPropertyChange(() => ChannelMap);
        }

        public void UpdateOrder(Models.ChannelNode channel, string number)
        {
            if (number.EndsWith("\r\n") && channel != null)
            {
                int preset = -1;
                if(Int32.TryParse(number.TrimEnd(), out preset))
                {
                    var channelList = _channelMap.ToList();
                    int oldChannel = channelList.FindIndex(c => c.PresetNumber == preset);
                    int currentChannel = channelList.IndexOf(channel);

                    channelList.RemoveAt(currentChannel);
                    
                    if (oldChannel < 0)
                    {
                        //there is no channel at given number
                    }
                    else
                    {
                        if (oldChannel > currentChannel)
                        {
                            int lastPreset = _channelMap[oldChannel].PresetNumber;

                            for (int i = oldChannel-1; i >= currentChannel; i--)
                            {
                                if (lastPreset > channelList[i].PresetNumber)
                                    break;
                                lastPreset = --channelList[i].PresetNumber;
                            }
                        }
                        else
                        {
                            int lastPreset = channelList[oldChannel].PresetNumber;

                            for (int i = oldChannel; i < currentChannel; i++)
                            {
                                if (lastPreset+1 < channelList[i].PresetNumber)
                                    break;
                                lastPreset = ++channelList[i].PresetNumber;
                            }
                        }
                    }
                    channel.PresetNumber = preset;
                    int newIndex = channelList.BinarySearch(channel);
                    channelList.Insert(~newIndex, channel);

                    ChannelMap = new ObservableCollection<Models.ChannelNode>(channelList);
                }
            }
        }
        

        public void RemoveEmptyChannels()
        {
            int i = 1;
            var channelList = _channelMap.ToList();
            channelList.RemoveAll(n => n.Name.StartsWith("--"));
            foreach (var channel in channelList)
            {
                channel.PresetNumber = i;
                i++;
            }
            ChannelMap = new ObservableCollection<Models.ChannelNode>(channelList);
        }

    }
}
